package com.caits.lbs.bean.dbmodel;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.caits.lbs.framework.log.CommonLogFactory;
import com.caits.lbs.framework.services.jmx.ILogSetable;
import com.caits.lbs.framework.utils.ClassUtils;
import com.caits.lbs.framework.utils.JsonUtils;

/**
 * <p>
 * ETBase
 * </p>
 * <p>
 * 所有业务实体的基础类，实现序列化
 * </p>
 * @author 周华彬(zhouhuabin@ctfo.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhb</td>
 *          <td>2011-4-1 下午05:13:35</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */
public class ETBase implements Serializable, ILogSetable, Cloneable {
	/** TODO */
	private static final long serialVersionUID = 1L;

	/** 日值类 */
	protected transient Logger log = CommonLogFactory.getLog();

	/** id */
	private String id;

	/**
	 * 构造器
	 */
	public ETBase() {
		// TODO Auto-generated constructor stub
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString() */
	@Override
	public final String toString() {
		return "待实现";
	}

	/**
	 * 将对象转换为json格式
	 * @return String
	 */
	public final String toJSONString() {
		try {
			return JsonUtils.getJsonStringFromObject(this);
		} catch (Exception e) {
			log.error("对象转换为json错误," + e.getLocalizedMessage());
			return "{\"msg\":\"" + e.getLocalizedMessage() + "\"}";
		}
	}

	/**
	 * 用反射以xml形式输出
	 * @return String
	 */
	public final String toXml() {
		return toElement().asXML();
	}

	/**
	 * 将属性转换为xml属性，忽略掉注解中的属性
	 * @return Element
	 */
	public final Element toElementUseAnnotation() {
		Element ele = DocumentHelper.createElement(getClass().getSimpleName().toLowerCase());
		XmlIgnoreFieldsAnnotation anotation = getClass().getAnnotation(XmlIgnoreFieldsAnnotation.class);
		List<String> list = anotation == null ? null : Arrays.asList(anotation.value());
		PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(this);
		for (int i = 0; i < pds.length; i++) {
			String key = pds[i].getName();
			// 这里不进行级联查找属性
			if (ETBase.class.isAssignableFrom(pds[i].getPropertyType())) {
				continue;
			}
			if (list != null && list.contains(key)) {
				continue;
			}
			try {
				Object obj = PropertyUtils.getProperty(this, key);
				if (obj == null) {
					obj = "";
				}
				ele.addAttribute(key, obj.toString());
			} catch (IllegalArgumentException e) {
				log.error("parseElement IllegalArgumentException:" + e.getLocalizedMessage() + " property:" + key, e);

			} catch (IllegalAccessException e) {
				log.error("parseElement IllegalAccessException:" + e.getLocalizedMessage() + " property:" + key, e);
			} catch (InvocationTargetException e) {
				log.error("parseElement InvocationTargetException:" + e.getLocalizedMessage() + " property:" + key, e);
			} catch (NoSuchMethodException e) {
				log.error("parseElement NoSuchMethodException:" + e.getLocalizedMessage() + " property:" + key, e);
			}
		}
		return ele;
	}

	/**
	 * 用反射以Element形式输出
	 * @return Element
	 */
	public final Element toElement() {
		Element ele = DocumentHelper.createElement(getClass().getSimpleName().toLowerCase());

		PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(this);

		for (int i = 0; i < pds.length; i++) {
			String key = pds[i].getName();
			// 这里不进行级联查找属性
			if (ETBase.class.isAssignableFrom(pds[i].getPropertyType())) {
				continue;
			}
			if (pds[i].getName().toLowerCase().equalsIgnoreCase("class")) {
				continue;
			}
			try {
				Object obj = PropertyUtils.getProperty(this, key);
				if (obj == null) {
					obj = "";
				}
				ele.addAttribute(key, obj.toString());

			} catch (IllegalArgumentException e) {
				log.error("parseElement IllegalArgumentException:" + e.getLocalizedMessage() + " property:" + key, e);

			} catch (IllegalAccessException e) {
				log.error("parseElement IllegalAccessException:" + e.getLocalizedMessage() + " property:" + key, e);
			} catch (InvocationTargetException e) {
				log.error("parseElement InvocationTargetException:" + e.getLocalizedMessage() + " property:" + key, e);
			} catch (NoSuchMethodException e) {
				log.error("parseElement NoSuchMethodException:" + e.getLocalizedMessage() + " property:" + key, e);
			}
		}
		return ele;
	}

	/**
	 * 根据字符串列表中的属性值，用反射以Element形式输出，不区分大小写
	 * @param attrList 属性列表
	 * @return Element
	 */
	public final Element toElement(final List<String> attrList) {
		if (attrList == null) {
			return null;
		}
		// String[] atts = new String[attrList.size()];
		// toArray(atts);
		String[] atts = (String[]) attrList.toArray();
		return toElement(atts);
	}

	/**
	 * 根据指定属性值数组用反射以Element形式输出，属性名不区分大小写
	 * @param attributes 属性列表
	 * @return Element
	 */
	public final Element toElement(final String[] attributes) {
		Element ele = DocumentHelper.createElement(getClass().getSimpleName().toLowerCase());
		for (String attributeName : attributes) {
			try {
				Object obj = PropertyUtils.getProperty(this, attributeName);
				if (obj == null) {
					obj = "";
				}
				ele.addAttribute(attributeName, obj.toString());
			} catch (IllegalArgumentException e) {
				log.error("parseElement IllegalArgumentException:" + " property:" + attributeName + e.getLocalizedMessage(), e);
			} catch (IllegalAccessException e) {
				log.error("parseElement IllegalAccessException:" + " property:" + attributeName + e.getLocalizedMessage(), e);
			} catch (InvocationTargetException e) {
				log.error("parseElement InvocationTargetException:" + " property:" + attributeName + e.getLocalizedMessage(), e);
			} catch (NoSuchMethodException e) {
				log.error("parseElement NoSuchMethodException:" + e.getLocalizedMessage() + " property:" + attributeName, e);
			}
		}
		return ele;
	}

	/**
	 * 用反射解析Element元素，赋值同名的bean属性 属性参数支持String和基本类型
	 * @param ele 要解析的元素 ，目前只支持属性名称解析
	 */
	public final void parseElement(final Element ele) {
		if (ele == null) {
			return;
		}
		Method[] methods = this.getClass().getDeclaredMethods();
		try {
			for (Method method : methods) {
				if (!method.getName().startsWith("set")) {
					continue;
				}
				String obj = ele.attributeValue(method.getName().toLowerCase().substring(3));
				if (obj == null) {
					continue;
				}
				Class<?>[] paramTypes = method.getParameterTypes();
				if (paramTypes.length == 1) {
					if (paramTypes[0] == Integer.TYPE) {
						Integer paramInt = (Integer.parseInt(obj));
						method.invoke(this, new Object[] { paramInt });
					} else if (paramTypes[0] == String.class) {
						method.invoke(this, new Object[] { obj });
					} else if (paramTypes[0] == Long.TYPE) {
						Long paramLong = (Long.parseLong(obj));
						method.invoke(this, new Object[] { paramLong });
					} else if (paramTypes[0] == Boolean.TYPE) {
						Boolean paramBoolean = Boolean.parseBoolean(obj);
						method.invoke(this, new Object[] { paramBoolean });
					} else if (paramTypes[0] == Float.TYPE) {
						Float paramFloat = Float.parseFloat(obj);
						method.invoke(this, new Object[] { paramFloat });
					} else if (paramTypes[0] == Short.TYPE) {
						Short paramShort = Short.parseShort(obj);
						method.invoke(this, new Object[] { paramShort });
					} else {
						log.error("not recognized parameter type" + paramTypes[0].getName());
					}
				}
			}
		} catch (IllegalArgumentException e) {
			log.error("parseElement IllegalArgument:" + e.getLocalizedMessage(), e);
		} catch (IllegalAccessException e) {
			log.error("parseElement IllegalAccessException:" + e.getLocalizedMessage(), e);
		} catch (InvocationTargetException e) {
			log.error("parseElement InvocationTargetException:" + e.getLocalizedMessage(), e);
		}
		return;
	}

	/**
	 * 获取变量<code>id</code>的值
	 * @return 返回的数据类型是<code>String</code>
	 */
	public final String getId() {
		return id;
	}

	/**
	 * 设置变量<code> id</code> 的值
	 * @param pid <code>pid</code> 参数类型是<code>String</code>
	 */
	public final void setId(final String pid) {
		this.id = pid;
	}

	/**
	 * 将实例转换为map形式，以属性名为key
	 * @return	Map<String, Object>
	 */
	public final Map<String, Object> bean2map() {
		return ClassUtils.bean2map(this);
	}

	/**
	 * 设置日志级别
	 * @param level	整数级别
	 * @return String
	 */
	public final String setLevel(final int level) {
		org.apache.log4j.Level le = getLevel(level);
		log.warn(String.format("%s实例设置日志级别为%s", getId(), le.toString()));
		log.setLevel(le);
		return log.getLevel().toString();
	}

	/**
	 * 根据数值获取级别对象 
	 * @param level	整数级别
	 * @return org.apache.log4j.Level
	 */
	public static org.apache.log4j.Level getLevel(final int level) {
		org.apache.log4j.Level le = org.apache.log4j.Level.INFO;
		switch (level) {
		case 0:
			le = org.apache.log4j.Level.DEBUG;
			break;
		case 1:
			le = org.apache.log4j.Level.INFO;
			break;
		case 2:
			le = org.apache.log4j.Level.WARN;
			break;
		case 3:
			le = org.apache.log4j.Level.ERROR;
			break;
		case 4:
			le = org.apache.log4j.Level.FATAL;
			break;
		case 5:
			le = org.apache.log4j.Level.OFF;
			break;
		default:
			break;
		}
		return le;
	}
}
